﻿//using System;
//using System.Collections.Generic;
//using System.Text;
//using System.Reflection.Emit;
//using System.Reflection;
//using System.Collections;

//namespace Framework.Serializer.FastJson
//{
//    internal struct Getters
//    {
//        public string Name;
//        public Reflection.GenericGetter Getter;
//        public Type propertyType;
//    }

//    internal sealed class Reflection
//    {
//        public readonly static Reflection Instance = new Reflection();
//        private Reflection()
//        {
//        }

//        public bool ShowReadOnlyProperties = false;
//        internal delegate object GenericSetter(object target, object value);
//        internal delegate object GenericGetter(object obj);
//        private delegate object CreateObject();
        
//        private SafeDictionary<Type, string> _tyname = new SafeDictionary<Type, string>();
//        private SafeDictionary<string, Type> _typecache = new SafeDictionary<string, Type>();
//        private SafeDictionary<Type, CreateObject> _constrcache = new SafeDictionary<Type, CreateObject>();
//        private SafeDictionary<Type, List<Getters>> _getterscache = new SafeDictionary<Type, List<Getters>>();

//        #region [   PROPERTY GET SET   ]
//        internal string GetTypeAssemblyName(Type t)
//        {
//            string val = "";
//            if (_tyname.TryGetValue(t, out val))
//                return val;
//            else
//            {
//                string s = t.AssemblyQualifiedName;
//                _tyname.Add(t, s);
//                return s;
//            }
//        }

//        internal Type GetTypeFromCache(string typename)
//        {
//            Type val = null;
//            if (_typecache.TryGetValue(typename, out val))
//                return val;
//            else
//            {
//                Type t = Type.GetType(typename);
//                _typecache.Add(typename, t);
//                return t;
//            }
//        }

//        internal object FastCreateInstance(Type objtype)
//        {
//            try
//            {
//                CreateObject c = null;
//                if (_constrcache.TryGetValue(objtype, out c))
//                {
//                    return c();
//                }
//                else
//                {
//                    if (objtype.IsClass) 
//                    {
//                        DynamicMethod dynMethod = new DynamicMethod("_", objtype, null);
//                        ILGenerator ilGen = dynMethod.GetILGenerator();
//                        ilGen.Emit(OpCodes.Newobj, objtype.GetConstructor(Type.EmptyTypes));
//                        ilGen.Emit(OpCodes.Ret);
//                        c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject));
//                        _constrcache.Add(objtype, c);
//                    }
//                    else // structs
//                    {     
//                        DynamicMethod dynMethod = new DynamicMethod("_",
//                            MethodAttributes.Public | MethodAttributes.Static,
//                            CallingConventions.Standard,
//                            typeof(object),
//                            null,
//                            objtype, false);
//                        ILGenerator ilGen = dynMethod.GetILGenerator();
//                        var lv = ilGen.DeclareLocal(objtype);
//                        ilGen.Emit(OpCodes.Ldloca_S, lv);
//                        ilGen.Emit(OpCodes.Initobj, objtype);
//                        ilGen.Emit(OpCodes.Ldloc_0);
//                        ilGen.Emit(OpCodes.Box, objtype);
//                        ilGen.Emit(OpCodes.Ret);
//                        c = (CreateObject)dynMethod.CreateDelegate(typeof(CreateObject));
//                        _constrcache.Add(objtype, c);
//                    }
//                    return c();
//                }
//            }
//            catch (Exception exc)
//            {
//                throw new Exception(string.Format("Failed to fast create instance for type '{0}' from assemebly '{1}'",
//                    objtype.FullName, objtype.AssemblyQualifiedName), exc);
//            }
//        }

//        internal static GenericSetter CreateSetField(Type type, FieldInfo fieldInfo)
//        {
//            Type[] arguments = new Type[2];
//            arguments[0] = arguments[1] = typeof(object);

//            DynamicMethod dynamicSet = new DynamicMethod("_", typeof(object), arguments, type, true);
//            ILGenerator il = dynamicSet.GetILGenerator();

//            if (!type.IsClass) // structs
//            {
//                var lv = il.DeclareLocal(type); 
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Unbox_Any, type);
//                il.Emit(OpCodes.Stloc_0);
//                il.Emit(OpCodes.Ldloca_S, lv);
//                il.Emit(OpCodes.Ldarg_1);
//                if (fieldInfo.FieldType.IsClass)
//                    il.Emit(OpCodes.Castclass, fieldInfo.FieldType);
//                else
//                    il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
//                il.Emit(OpCodes.Stfld, fieldInfo);
//                il.Emit(OpCodes.Ldloc_0);
//                il.Emit(OpCodes.Box, type);
//                il.Emit(OpCodes.Ret);
//            }
//            else
//            {
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Ldarg_1);
//                if (fieldInfo.FieldType.IsValueType)
//                    il.Emit(OpCodes.Unbox_Any, fieldInfo.FieldType);
//                il.Emit(OpCodes.Stfld, fieldInfo);
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Ret);
//            }
//            return (GenericSetter)dynamicSet.CreateDelegate(typeof(GenericSetter));
//        }

//        internal static GenericSetter CreateSetMethod(Type type, PropertyInfo propertyInfo)
//        {
//            MethodInfo setMethod = propertyInfo.GetSetMethod();
//            if (setMethod == null)
//                return null;

//            Type[] arguments = new Type[2];
//            arguments[0] = arguments[1] = typeof(object);

//            DynamicMethod setter = new DynamicMethod("_", typeof(object), arguments);
//            ILGenerator il = setter.GetILGenerator();

//            if (!type.IsClass) // structs
//            {
//                var lv = il.DeclareLocal(type); 
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Unbox_Any, type);
//                il.Emit(OpCodes.Stloc_0);
//                il.Emit(OpCodes.Ldloca_S, lv);
//                il.Emit(OpCodes.Ldarg_1);
//                if (propertyInfo.PropertyType.IsClass)
//                    il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
//                else
//                    il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
//                il.EmitCall(OpCodes.Call, setMethod, null);
//                il.Emit(OpCodes.Ldloc_0);
//                il.Emit(OpCodes.Box, type);
//            }
//            else
//            {
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
//                il.Emit(OpCodes.Ldarg_1);
//                if (propertyInfo.PropertyType.IsClass)
//                    il.Emit(OpCodes.Castclass, propertyInfo.PropertyType);
//                else
//                    il.Emit(OpCodes.Unbox_Any, propertyInfo.PropertyType);
//                il.EmitCall(OpCodes.Callvirt, setMethod, null);
//                il.Emit(OpCodes.Ldarg_0);
//            }

//            il.Emit(OpCodes.Ret);

//            return (GenericSetter)setter.CreateDelegate(typeof(GenericSetter));
//        }

//        internal static GenericGetter CreateGetField(Type type, FieldInfo fieldInfo)
//        {
//            DynamicMethod dynamicGet = new DynamicMethod("_", typeof(object), new Type[] { typeof(object) }, type, true);
//            ILGenerator il = dynamicGet.GetILGenerator();

//            if (!type.IsClass) // structs
//            {
//                var lv = il.DeclareLocal(type);
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Unbox_Any, type);
//                il.Emit(OpCodes.Stloc_0);
//                il.Emit(OpCodes.Ldloca_S, lv);
//                il.Emit(OpCodes.Ldfld, fieldInfo);
//                if (fieldInfo.FieldType.IsValueType)
//                    il.Emit(OpCodes.Box, fieldInfo.FieldType);
//            }
//            else
//            {
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Ldfld, fieldInfo);
//                if (fieldInfo.FieldType.IsValueType)
//                    il.Emit(OpCodes.Box, fieldInfo.FieldType);
//            }

//            il.Emit(OpCodes.Ret);

//            return (GenericGetter)dynamicGet.CreateDelegate(typeof(GenericGetter));
//        }

//        internal static GenericGetter CreateGetMethod(Type type, PropertyInfo propertyInfo)
//        {
//            MethodInfo getMethod = propertyInfo.GetGetMethod();
//            if (getMethod == null)
//                return null;

//            Type[] arguments = new Type[1];
//            arguments[0] = typeof(object);

//            DynamicMethod getter = new DynamicMethod("_", typeof(object), arguments, type);
//            ILGenerator il = getter.GetILGenerator();
            
//            if (!type.IsClass) // structs
//            {
//                var lv = il.DeclareLocal(type);
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Unbox_Any, type);
//                il.Emit(OpCodes.Stloc_0);
//                il.Emit(OpCodes.Ldloca_S, lv);
//                il.EmitCall(OpCodes.Call, getMethod, null);
//                if (propertyInfo.PropertyType.IsValueType)
//                    il.Emit(OpCodes.Box, propertyInfo.PropertyType);
//            }
//            else
//            {
//                il.Emit(OpCodes.Ldarg_0);
//                il.Emit(OpCodes.Castclass, propertyInfo.DeclaringType);
//                il.EmitCall(OpCodes.Callvirt, getMethod, null);
//                if (propertyInfo.PropertyType.IsValueType)
//                    il.Emit(OpCodes.Box, propertyInfo.PropertyType);
//            }

//            il.Emit(OpCodes.Ret);

//            return (GenericGetter)getter.CreateDelegate(typeof(GenericGetter));
//        }

//        internal List<Getters> GetGetters(Type type)
//        {
//            List<Getters> val = null;
//            if (_getterscache.TryGetValue(type, out val))
//                return val;

//            PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
//            List<Getters> getters = new List<Getters>();
//            foreach (PropertyInfo p in props)
//            {
//                if (!p.CanWrite && ShowReadOnlyProperties == false) continue;
                
//                object[] att = p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false);
//                if (att != null && att.Length > 0)
//                    continue;

//                GenericGetter g = CreateGetMethod(type, p);
//                if (g != null)
//                {
//                    Getters gg = new Getters();
//                    gg.Name = p.Name;
//                    gg.Getter = g;
//                    gg.propertyType = p.PropertyType;
//                    getters.Add(gg);
//                }
//            }

//            FieldInfo[] fi = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
//            foreach (var f in fi)
//            {
//                object[] att = f.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false);
//                if (att != null && att.Length > 0)
//                    continue;

//                GenericGetter g = CreateGetField(type, f);
//                if (g != null)
//                {
//                    Getters gg = new Getters();
//                    gg.Name = f.Name;
//                    gg.Getter = g;
//                    gg.propertyType = f.FieldType;
//                    getters.Add(gg);
//                }
//            }

//            _getterscache.Add(type, getters);
//            return getters;
//        }

//        #endregion
//    }
//}
